// link https://www.jianshu.com/p/0837dde8dcd5
// a. 在函数体前通过关键字async可以将函数变为async函数
// b. 在async函数中对需要异步执行的函数前需加await关键字
// c. await后的函数必须使用Promise对象封装
// d. async函数执行后返回的是一个Promise对象

var delay_print_first = function(){
    return "First";
}
var delay_print_second = function(){
    return Promise.resolve("Second")
}
var delay_print_third = function(){
    return Promise.resolve("Third")
}
var async_status = async function(ms){
    try{
        var first = await delay_print_first();
        var send = await delay_print_second();
        var third = await delay_print_third();
        return first + " " + send + " " + third;
    } catch (error) {
        return Promise.reject("Some error")
    }
}
async_status().then((ret) => {
    console.log(ret)
}).catch((err) => {
    console.log(err)
})
//  为了有效的记录下error的信息，通常会在async执行后做一些Promise catch的处理


var Delay_Time = function(ms) {
    return new Promise(function(resolve){
        setTimeout(resolve, ms)
    })
}
var Delay_Time_Second = function(ms){
    setTimeout(function(){}, ms)
}
var Delay_Print = async function(ms){
    Delay_Time_Second(2000)
    console.log("After Delay_Time_Second")
    await Delay_Time(ms)
    console.log("After Delay_Time")

    return "END"
    // return Promise.resolve("END")
    // return await "END"
    // return new Promise(function(resolve, reject){
    //     resolve("END")
    // })
}
Delay_Print(2000).then(function(resolve){
    console.log(resolve)
})
//  在正常的情况下，await后是一个Promise对象。如果不是就会立马转换成一个立即resolve的Promise对象


var delay_time = function(ms, param) {
    return new Promise(function(resolve){
        setTimeout(function(){
            console.log(new Date().getTime())
            resolve(param)
        }, ms)
    })
}
var asyn_fun = async function(param) {
    var time_out = 1000;
    const results = await param.map(async param => {
        time_out = time_out + 1000;
        var out = await delay_time(time_out, param)
        return out
    })
    var target = [];
    for (var ret of results){
        target.push(await ret)
    }
    return await target
}
asyn_fun(['First', 'Second', 'Third', 'Last']).then(function(result){
    console.log(JSON.stringify(result))
})
//  虽然map方法的参数是async函数，但它是并发执行的，因为只有async函数内部是继发执行，外部不受影响。后面的for..of循环内部使用了await，因此实现了按顺序输出


async function rejectionWithReturnAwait() {
    try{
        return await Promise.reject(new Error())
    } catch (e){
        return "Saved"
    }
}
rejectionWithReturnAwait().then((ret) => {
    console.log(ret)
})
//  这段代码在async方法体中通过try/catch捕获被await声明并且状态是rejected的Promise对象，捕获异常后返回立即执行的Promise对象


async function rejectionWithReturn(){
    try{
        return Promise.reject(new Error())
    } catch (e){
        return "Saved"
    }
}
rejectionWithReturn().then((ret) => {
    console.log(ret)
})
//  上面async代码快内的Promise对象没有使用await关键字声明，因为当Promise对象的状态由pending变成rejected后并不能try/catch捕获